home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16_Src.lha / Python16_Source / Modules / signalmodule.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-03  |  14.6 KB  |  665 lines

  1. /* Signal module -- many thanks to Lance Ellinghaus */
  2.  
  3. /* XXX Signals should be recorded per thread, now we have thread state. */
  4.  
  5. #include "Python.h"
  6. #include "intrcheck.h"
  7.  
  8. #ifdef MS_WIN32
  9. #include <process.h>
  10. #endif
  11.  
  12. #ifdef HAVE_UNISTD_H
  13. #include <unistd.h>
  14. #endif
  15.  
  16. #include <signal.h>
  17.  
  18. #ifndef SIG_ERR
  19. #define SIG_ERR ((RETSIGTYPE (*)())-1)
  20. #endif
  21.  
  22. #if defined(PYOS_OS2)
  23. #define NSIG 12
  24. #include <process.h>
  25. #endif
  26.  
  27. #ifndef NSIG
  28. #ifdef _SIGMAX
  29. #define NSIG (_SIGMAX + 1)    /* For QNX */
  30. #else
  31. #define NSIG (SIGMAX + 1)    /* for djgpp */
  32. #endif
  33. #endif
  34.  
  35.  
  36.  
  37. /*
  38.    NOTES ON THE INTERACTION BETWEEN SIGNALS AND THREADS
  39.  
  40.    When threads are supported, we want the following semantics:
  41.  
  42.    - only the main thread can set a signal handler
  43.    - any thread can get a signal handler
  44.    - signals are only delivered to the main thread
  45.  
  46.    I.e. we don't support "synchronous signals" like SIGFPE (catching
  47.    this doesn't make much sense in Python anyway) nor do we support
  48.    signals as a means of inter-thread communication, since not all
  49.    thread implementations support that (at least our thread library
  50.    doesn't).
  51.  
  52.    We still have the problem that in some implementations signals
  53.    generated by the keyboard (e.g. SIGINT) are delivered to all
  54.    threads (e.g. SGI), while in others (e.g. Solaris) such signals are
  55.    delivered to one random thread (an intermediate possibility would
  56.    be to deliver it to the main thread -- POSIX?).  For now, we have
  57.    a working implementation that works in all three cases -- the
  58.    handler ignores signals if getpid() isn't the same as in the main
  59.    thread.  XXX This is a hack.
  60.  
  61. */
  62.  
  63. #ifdef WITH_THREAD
  64. #include <sys/types.h> /* For pid_t */
  65. #include "pythread.h"
  66. static long main_thread;
  67. static pid_t main_pid;
  68. #endif
  69.  
  70. static struct {
  71.         int tripped;
  72.         PyObject *func;
  73. } Handlers[NSIG];
  74.  
  75. static int is_tripped = 0; /* Speed up sigcheck() when none tripped */
  76.  
  77. static PyObject *DefaultHandler;
  78. static PyObject *IgnoreHandler;
  79. static PyObject *IntHandler;
  80.  
  81. static RETSIGTYPE (*old_siginthandler)() = SIG_DFL;
  82.  
  83.  
  84.  
  85. static PyObject *
  86. signal_default_int_handler(self, arg)
  87.     PyObject *self;
  88.     PyObject *arg;
  89. {
  90.     PyErr_SetNone(PyExc_KeyboardInterrupt);
  91.     return NULL;
  92. }
  93.  
  94. static char default_int_handler_doc[] =
  95. "default_int_handler(...)\n\
  96. \n\
  97. The default handler for SIGINT instated by Python.\n\
  98. It raises KeyboardInterrupt.";
  99.  
  100.  
  101. static RETSIGTYPE
  102. signal_handler(sig_num)
  103.     int sig_num;
  104. {
  105. #ifdef WITH_THREAD
  106.     /* See NOTES section above */
  107.     if (getpid() == main_pid) {
  108. #endif
  109.         is_tripped++;
  110.         Handlers[sig_num].tripped = 1;
  111.         Py_AddPendingCall(
  112.             (int (*) Py_PROTO((ANY *)))PyErr_CheckSignals, NULL);
  113. #ifdef WITH_THREAD
  114.     }
  115. #endif
  116. #ifdef SIGCHLD
  117.     if (sig_num == SIGCHLD) {
  118.         /* To avoid infinite recursion, this signal remains
  119.            reset until explicit re-instated.
  120.            Don't clear the 'func' field as it is our pointer
  121.            to the Python handler... */
  122.         return;
  123.     }
  124. #endif
  125. #ifdef HAVE_SIGINTERRUPT
  126.     siginterrupt(sig_num, 1);
  127. #endif
  128.     (void)signal(sig_num, &signal_handler);
  129. }
  130.  
  131.  
  132.  
  133. #ifdef HAVE_ALARM
  134. static PyObject *
  135. signal_alarm(self, args)
  136.     PyObject *self; /* Not used */
  137.     PyObject *args;
  138. {
  139.     int t;
  140.     if (!PyArg_Parse(args, "i", &t))
  141.         return NULL;
  142.     /* alarm() returns the number of seconds remaining */
  143.     return PyInt_FromLong(alarm(t));
  144. }
  145.  
  146. static char alarm_doc[] =
  147. "alarm(seconds)\n\
  148. \n\
  149. Arrange for SIGALRM to arrive after the given number of seconds.";
  150. #endif
  151.  
  152. #ifdef HAVE_PAUSE
  153. static PyObject *
  154. signal_pause(self, args)
  155.     PyObject *self; /* Not used */
  156.     PyObject *args;
  157. {
  158.     if (!PyArg_NoArgs(args))
  159.         return NULL;
  160.  
  161.     Py_BEGIN_ALLOW_THREADS
  162.     (void)pause();
  163.     Py_END_ALLOW_THREADS
  164.     /* make sure that any exceptions that got raised are propagated
  165.      * back into Python
  166.      */
  167.     if (PyErr_CheckSignals())
  168.         return NULL;
  169.  
  170.     Py_INCREF(Py_None);
  171.     return Py_None;
  172. }
  173. static char pause_doc[] =
  174. "pause()\n\
  175. \n\
  176. Wait until a signal arrives.";
  177.  
  178. #endif
  179.  
  180.  
  181. static PyObject *
  182. signal_signal(self, args)
  183.     PyObject *self; /* Not used */
  184.     PyObject *args;
  185. {
  186.     PyObject *obj;
  187.     int sig_num;
  188.     PyObject *old_handler;
  189.     RETSIGTYPE (*func)();
  190.     if (!PyArg_Parse(args, "(iO)", &sig_num, &obj))
  191.         return NULL;
  192. #ifdef WITH_THREAD
  193.     if (PyThread_get_thread_ident() != main_thread) {
  194.         PyErr_SetString(PyExc_ValueError,
  195.                 "signal only works in main thread");
  196.         return NULL;
  197.     }
  198. #endif
  199.     if (sig_num < 1 || sig_num >= NSIG) {
  200.         PyErr_SetString(PyExc_ValueError,
  201.                 "signal number out of range");
  202.         return NULL;
  203.     }
  204.     if (obj == IgnoreHandler)
  205.         func = SIG_IGN;
  206.     else if (obj == DefaultHandler)
  207.         func = SIG_DFL;
  208.     else if (!PyCallable_Check(obj)) {
  209.         PyErr_SetString(PyExc_TypeError,
  210. "signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object");
  211.         return NULL;
  212.     }
  213.     else
  214.         func = signal_handler;
  215. #ifdef HAVE_SIGINTERRUPT
  216.     siginterrupt(sig_num, 1);
  217. #endif
  218.     if (signal(sig_num, func) == SIG_ERR) {
  219.         PyErr_SetFromErrno(PyExc_RuntimeError);
  220.         return NULL;
  221.     }
  222.     old_handler = Handlers[sig_num].func;
  223.     Handlers[sig_num].tripped = 0;
  224.     Py_INCREF(obj);
  225.     Handlers[sig_num].func = obj;
  226.     return old_handler;
  227. }
  228.  
  229. static char signal_doc[] =
  230. "signal(sig, action) -> action\n\
  231. \n\
  232. Set the action for the given signal.  The action can be SIG_DFL,\n\
  233. SIG_IGN, or a callable Python object.  The previous action is\n\
  234. returned.  See getsignal() for possible return values.\n\
  235. \n\
  236. *** IMPORTANT NOTICE ***\n\
  237. A signal handler function is called with two arguments:\n\
  238. the first is the signal number, the second is the interrupted stack frame.";
  239.  
  240.  
  241. static PyObject *
  242. signal_getsignal(self, args)
  243.     PyObject *self; /* Not used */
  244.     PyObject *args;
  245. {
  246.     int sig_num;
  247.     PyObject *old_handler;
  248.     if (!PyArg_Parse(args, "i", &sig_num))
  249.         return NULL;
  250.     if (sig_num < 1 || sig_num >= NSIG) {
  251.         PyErr_SetString(PyExc_ValueError,
  252.                 "signal number out of range");
  253.         return NULL;
  254.     }
  255.     old_handler = Handlers[sig_num].func;
  256.     Py_INCREF(old_handler);
  257.     return old_handler;
  258. }
  259.  
  260. static char getsignal_doc[] =
  261. "getsignal(sig) -> action\n\
  262. \n\
  263. Return the current action for the given signal.  The return value can be:\n\
  264. SIG_IGN -- if the signal is being ignored\n\
  265. SIG_DFL -- if the default action for the signal is in effect\n\
  266. None -- if an unknown handler is in effect\n\
  267. anything else -- the callable Python object used as a handler\n\
  268. ";
  269.  
  270.  
  271. /* List of functions defined in the module */
  272. static PyMethodDef signal_methods[] = {
  273. #ifdef HAVE_ALARM
  274.     {"alarm",            signal_alarm, 0, alarm_doc},
  275. #endif
  276.     {"signal",            signal_signal, 0, signal_doc},
  277.     {"getsignal",            signal_getsignal, 0, getsignal_doc},
  278. #ifdef HAVE_PAUSE
  279.     {"pause",            signal_pause, 0, pause_doc},
  280. #endif
  281.     {"default_int_handler", signal_default_int_handler, 0,
  282.                 default_int_handler_doc},
  283.     {NULL,            NULL}        /* sentinel */
  284. };
  285.  
  286.  
  287.  
  288. static char module_doc[] =
  289. "This module provides mechanisms to use signal handlers in Python.\n\
  290. \n\
  291. Functions:\n\
  292. \n\
  293. alarm() -- cause SIGALRM after a specified time [Unix only]\n\
  294. signal() -- set the action for a given signal\n\
  295. getsignal() -- get the signal action for a given signal\n\
  296. pause() -- wait until a signal arrives [Unix only]\n\
  297. default_int_handler() -- default SIGINT handler\n\
  298. \n\
  299. Constants:\n\
  300. \n\
  301. SIG_DFL -- used to refer to the system default handler\n\
  302. SIG_IGN -- used to ignore the signal\n\
  303. NSIG -- number of defined signals\n\
  304. \n\
  305. SIGINT, SIGTERM, etc. -- signal numbers\n\
  306. \n\
  307. *** IMPORTANT NOTICE ***\n\
  308. A signal handler function is called with two arguments:\n\
  309. the first is the signal number, the second is the interrupted stack frame.";
  310.  
  311. DL_EXPORT(void)
  312. initsignal()
  313. {
  314.     PyObject *m, *d, *x;
  315.     int i;
  316.  
  317. #ifdef WITH_THREAD
  318.     main_thread = PyThread_get_thread_ident();
  319.     main_pid = getpid();
  320. #endif
  321.  
  322.     /* Create the module and add the functions */
  323.     m = Py_InitModule3("signal", signal_methods, module_doc);
  324.  
  325.     /* Add some symbolic constants to the module */
  326.     d = PyModule_GetDict(m);
  327.  
  328.     x = DefaultHandler = PyInt_FromLong((long)SIG_DFL);
  329.         if (!x || PyDict_SetItemString(d, "SIG_DFL", x) < 0)
  330.                 goto finally;
  331.  
  332.     x = IgnoreHandler = PyInt_FromLong((long)SIG_IGN);
  333.         if (!x || PyDict_SetItemString(d, "SIG_IGN", x) < 0)
  334.                 goto finally;
  335.  
  336.         x = PyInt_FromLong((long)NSIG);
  337.         if (!x || PyDict_SetItemString(d, "NSIG", x) < 0)
  338.                 goto finally;
  339.         Py_DECREF(x);
  340.  
  341.     x = IntHandler = PyDict_GetItemString(d, "default_int_handler");
  342.         if (!x)
  343.                 goto finally;
  344.     Py_INCREF(IntHandler);
  345.  
  346.     Handlers[0].tripped = 0;
  347.     for (i = 1; i < NSIG; i++) {
  348.         RETSIGTYPE (*t)();
  349. #ifdef HAVE_SIGACTION
  350.         struct sigaction act;
  351.         sigaction(i,  0, &act);
  352.         t = act.sa_handler;
  353. #else
  354.         t = signal(i, SIG_IGN);
  355.         signal(i, t);
  356. #endif
  357.         Handlers[i].tripped = 0;
  358.         if (t == SIG_DFL)
  359.             Handlers[i].func = DefaultHandler;
  360.         else if (t == SIG_IGN)
  361.             Handlers[i].func = IgnoreHandler;
  362.         else
  363.             Handlers[i].func = Py_None; /* None of our business */
  364.         Py_INCREF(Handlers[i].func);
  365.     }
  366.     if (Handlers[SIGINT].func == DefaultHandler) {
  367.         /* Install default int handler */
  368.         Py_INCREF(IntHandler);
  369.         Py_DECREF(Handlers[SIGINT].func);
  370.         Handlers[SIGINT].func = IntHandler;
  371.         old_siginthandler = signal(SIGINT, &signal_handler);
  372.     }
  373.  
  374. #ifdef SIGHUP
  375.     x = PyInt_FromLong(SIGHUP);
  376.     PyDict_SetItemString(d, "SIGHUP", x);
  377.         Py_XDECREF(x);
  378. #endif
  379. #ifdef SIGINT
  380.     x = PyInt_FromLong(SIGINT);
  381.     PyDict_SetItemString(d, "SIGINT", x);
  382.         Py_XDECREF(x);
  383. #endif
  384. #ifdef SIGQUIT
  385.     x = PyInt_FromLong(SIGQUIT);
  386.     PyDict_SetItemString(d, "SIGQUIT", x);
  387.         Py_XDECREF(x);
  388. #endif
  389. #ifdef SIGILL
  390.     x = PyInt_FromLong(SIGILL);
  391.     PyDict_SetItemString(d, "SIGILL", x);
  392.         Py_XDECREF(x);
  393. #endif
  394. #ifdef SIGTRAP
  395.     x = PyInt_FromLong(SIGTRAP);
  396.     PyDict_SetItemString(d, "SIGTRAP", x);
  397.         Py_XDECREF(x);
  398. #endif
  399. #ifdef SIGIOT
  400.     x = PyInt_FromLong(SIGIOT);
  401.     PyDict_SetItemString(d, "SIGIOT", x);
  402.         Py_XDECREF(x);
  403. #endif
  404. #ifdef SIGABRT
  405.     x = PyInt_FromLong(SIGABRT);
  406.     PyDict_SetItemString(d, "SIGABRT", x);
  407.         Py_XDECREF(x);
  408. #endif
  409. #ifdef SIGEMT
  410.     x = PyInt_FromLong(SIGEMT);
  411.     PyDict_SetItemString(d, "SIGEMT", x);
  412.         Py_XDECREF(x);
  413. #endif
  414. #ifdef SIGFPE
  415.     x = PyInt_FromLong(SIGFPE);
  416.     PyDict_SetItemString(d, "SIGFPE", x);
  417.         Py_XDECREF(x);
  418. #endif
  419. #ifdef SIGKILL
  420.     x = PyInt_FromLong(SIGKILL);
  421.     PyDict_SetItemString(d, "SIGKILL", x);
  422.         Py_XDECREF(x);
  423. #endif
  424. #ifdef SIGBUS
  425.     x = PyInt_FromLong(SIGBUS);
  426.     PyDict_SetItemString(d, "SIGBUS", x);
  427.         Py_XDECREF(x);
  428. #endif
  429. #ifdef SIGSEGV
  430.     x = PyInt_FromLong(SIGSEGV);
  431.     PyDict_SetItemString(d, "SIGSEGV", x);
  432.         Py_XDECREF(x);
  433. #endif
  434. #ifdef SIGSYS
  435.     x = PyInt_FromLong(SIGSYS);
  436.     PyDict_SetItemString(d, "SIGSYS", x);
  437.         Py_XDECREF(x);
  438. #endif
  439. #ifdef SIGPIPE
  440.     x = PyInt_FromLong(SIGPIPE);
  441.     PyDict_SetItemString(d, "SIGPIPE", x);
  442.         Py_XDECREF(x);
  443. #endif
  444. #ifdef SIGALRM
  445.     x = PyInt_FromLong(SIGALRM);
  446.     PyDict_SetItemString(d, "SIGALRM", x);
  447.         Py_XDECREF(x);
  448. #endif
  449. #ifdef SIGTERM
  450.     x = PyInt_FromLong(SIGTERM);
  451.     PyDict_SetItemString(d, "SIGTERM", x);
  452.         Py_XDECREF(x);
  453. #endif
  454. #ifdef SIGUSR1
  455.     x = PyInt_FromLong(SIGUSR1);
  456.     PyDict_SetItemString(d, "SIGUSR1", x);
  457.         Py_XDECREF(x);
  458. #endif
  459. #ifdef SIGUSR2
  460.     x = PyInt_FromLong(SIGUSR2);
  461.     PyDict_SetItemString(d, "SIGUSR2", x);
  462.         Py_XDECREF(x);
  463. #endif
  464. #ifdef SIGCLD
  465.     x = PyInt_FromLong(SIGCLD);
  466.     PyDict_SetItemString(d, "SIGCLD", x);
  467.         Py_XDECREF(x);
  468. #endif
  469. #ifdef SIGCHLD
  470.     x = PyInt_FromLong(SIGCHLD);
  471.     PyDict_SetItemString(d, "SIGCHLD", x);
  472.         Py_XDECREF(x);
  473. #endif
  474. #ifdef SIGPWR
  475.     x = PyInt_FromLong(SIGPWR);
  476.     PyDict_SetItemString(d, "SIGPWR", x);
  477.         Py_XDECREF(x);
  478. #endif
  479. #ifdef SIGIO
  480.     x = PyInt_FromLong(SIGIO);
  481.     PyDict_SetItemString(d, "SIGIO", x);
  482.         Py_XDECREF(x);
  483. #endif
  484. #ifdef SIGURG
  485.     x = PyInt_FromLong(SIGURG);
  486.     PyDict_SetItemString(d, "SIGURG", x);
  487.         Py_XDECREF(x);
  488. #endif
  489. #ifdef SIGWINCH
  490.     x = PyInt_FromLong(SIGWINCH);
  491.     PyDict_SetItemString(d, "SIGWINCH", x);
  492.         Py_XDECREF(x);
  493. #endif
  494. #ifdef SIGPOLL
  495.     x = PyInt_FromLong(SIGPOLL);
  496.     PyDict_SetItemString(d, "SIGPOLL", x);
  497.         Py_XDECREF(x);
  498. #endif
  499. #ifdef SIGSTOP
  500.     x = PyInt_FromLong(SIGSTOP);
  501.     PyDict_SetItemString(d, "SIGSTOP", x);
  502.         Py_XDECREF(x);
  503. #endif
  504. #ifdef SIGTSTP
  505.     x = PyInt_FromLong(SIGTSTP);
  506.     PyDict_SetItemString(d, "SIGTSTP", x);
  507.         Py_XDECREF(x);
  508. #endif
  509. #ifdef SIGCONT
  510.     x = PyInt_FromLong(SIGCONT);
  511.     PyDict_SetItemString(d, "SIGCONT", x);
  512.         Py_XDECREF(x);
  513. #endif
  514. #ifdef SIGTTIN
  515.     x = PyInt_FromLong(SIGTTIN);
  516.     PyDict_SetItemString(d, "SIGTTIN", x);
  517.         Py_XDECREF(x);
  518. #endif
  519. #ifdef SIGTTOU
  520.     x = PyInt_FromLong(SIGTTOU);
  521.     PyDict_SetItemString(d, "SIGTTOU", x);
  522.         Py_XDECREF(x);
  523. #endif
  524. #ifdef SIGVTALRM
  525.     x = PyInt_FromLong(SIGVTALRM);
  526.     PyDict_SetItemString(d, "SIGVTALRM", x);
  527.         Py_XDECREF(x);
  528. #endif
  529. #ifdef SIGPROF
  530.     x = PyInt_FromLong(SIGPROF);
  531.     PyDict_SetItemString(d, "SIGPROF", x);
  532.         Py_XDECREF(x);
  533. #endif
  534. #ifdef SIGXCPU
  535.     x = PyInt_FromLong(SIGXCPU);
  536.     PyDict_SetItemString(d, "SIGXCPU", x);
  537.         Py_XDECREF(x);
  538. #endif
  539. #ifdef SIGXFSZ
  540.     x = PyInt_FromLong(SIGXFSZ);
  541.     PyDict_SetItemString(d, "SIGXFSZ", x);
  542.         Py_XDECREF(x);
  543. #endif
  544.         if (!PyErr_Occurred())
  545.                 return;
  546.  
  547.     /* Check for errors */
  548.   finally:
  549.         return;
  550. }
  551.  
  552. static void
  553. finisignal()
  554. {
  555.     int i;
  556.     PyObject *func;
  557.  
  558.     signal(SIGINT, old_siginthandler);
  559.     old_siginthandler = SIG_DFL;
  560.  
  561.     for (i = 1; i < NSIG; i++) {
  562.         func = Handlers[i].func;
  563.         Handlers[i].tripped = 0;
  564.         Handlers[i].func = NULL;
  565.         if (i != SIGINT && func != NULL && func != Py_None &&
  566.             func != DefaultHandler && func != IgnoreHandler)
  567.             signal(i, SIG_DFL);
  568.         Py_XDECREF(func);
  569.     }
  570.  
  571.     Py_XDECREF(IntHandler);
  572.     IntHandler = NULL;
  573.     Py_XDECREF(DefaultHandler);
  574.     DefaultHandler = NULL;
  575.     Py_XDECREF(IgnoreHandler);
  576.     IgnoreHandler = NULL;
  577. }
  578.  
  579.  
  580.  
  581. /* Declared in pyerrors.h */
  582. int
  583. PyErr_CheckSignals()
  584. {
  585.     int i;
  586.     PyObject *f;
  587.  
  588.     if (!is_tripped)
  589.         return 0;
  590. #ifdef WITH_THREAD
  591.     if (PyThread_get_thread_ident() != main_thread)
  592.         return 0;
  593. #endif
  594.     if (!(f = PyEval_GetFrame()))
  595.         f = Py_None;
  596.     
  597.     for (i = 1; i < NSIG; i++) {
  598.         if (Handlers[i].tripped) {
  599.             PyObject *result = NULL;
  600.             PyObject *arglist = Py_BuildValue("(iO)", i, f);
  601.             Handlers[i].tripped = 0;
  602.  
  603.             if (arglist) {
  604.                 result = PyEval_CallObject(Handlers[i].func,
  605.                                arglist);
  606.                 Py_DECREF(arglist);
  607.             }
  608.             if (!result)
  609.                 return -1;
  610.  
  611.             Py_DECREF(result);
  612.         }
  613.     }
  614.     is_tripped = 0;
  615.     return 0;
  616. }
  617.  
  618.  
  619. /* Replacements for intrcheck.c functionality
  620.  * Declared in pyerrors.h
  621.  */
  622. void
  623. PyErr_SetInterrupt()
  624. {
  625.     is_tripped++;
  626.     Handlers[SIGINT].tripped = 1;
  627.     Py_AddPendingCall((int (*) Py_PROTO((ANY *)))PyErr_CheckSignals, NULL);
  628. }
  629.  
  630. void
  631. PyOS_InitInterrupts()
  632. {
  633.     initsignal();
  634.     _PyImport_FixupExtension("signal", "signal");
  635. }
  636.  
  637. void
  638. PyOS_FiniInterrupts()
  639. {
  640.     finisignal();
  641. }
  642.  
  643. int
  644. PyOS_InterruptOccurred()
  645. {
  646.     if (Handlers[SIGINT].tripped) {
  647. #ifdef WITH_THREAD
  648.         if (PyThread_get_thread_ident() != main_thread)
  649.             return 0;
  650. #endif
  651.         Handlers[SIGINT].tripped = 0;
  652.         return 1;
  653.     }
  654.     return 0;
  655. }
  656.  
  657. void
  658. PyOS_AfterFork()
  659. {
  660. #ifdef WITH_THREAD
  661.     main_thread = PyThread_get_thread_ident();
  662.     main_pid = getpid();
  663. #endif
  664. }
  665.